﻿using CommonModel.Util;
using GXRTBTC.PublicClassLibrary.Util;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GXRTBTC.PublicClassLibrary.Model
{
    /// <summary>
    /// 告警模型
    /// </summary>
    public class RealAlarmModel
    {
        /// <summary>
        /// 告警唯一key
        /// 此处默认32位uuid
        /// </summary>
        public string alarmKey { get; set; } = System.Guid.NewGuid().ToString("N").ToUpper();
        /// <summary>
        /// 告警父级key
        /// </summary>
        public string parentAlarmKey { get; set; } = "";
        /// <summary>
        /// 是否需要update 是否更新条目
        /// 当前主要用于判断parentAlarmKey是否修改
        /// </summary>
        public bool isUpdate { get; set; } = false;
        /// <summary>
        /// 20230109 是否关联衍生告警，动态表定义的
        /// </summary>
        public bool isRelation { get; set; } = false;
        /// <summary>
        /// 告警开关，0：不产生告警；1：产生告警并推送；2：产生告警但不推送
        /// 对应动态表is_open参数，默认是1，0时不产生自身
        /// </summary>
        public int isOpen { get; set; } = 1;
        /// <summary>
        /// 每一条告警唯一key
        /// 衍生告警：台站ID+衍生告警字符串+衍生告警ID
        /// 普通告警：上一级系统名称+工位号+告警字段名称
        /// </summary>
        public string alarmCode { get; set; } = "";
        /// <summary>
        /// 告警ID，alarm_basic_info表对应
        /// </summary>
        public int alarmId { get; set; } = -1;
        /// <summary>
        /// 告警类型
        /// </summary>
        public string alarmType { get; set; } = "";
        /// <summary>
        /// 告警名称，用于辨别工位号下具体某个告警
        /// 对应dynamic_data表para_name
        /// </summary>
        public string alarmName { get; set; } = "";
        /// <summary>
        /// 告警标题、描述，对应dynamic_data表alarm_title
        /// </summary>
        public string alarmTitle { get; set; } = "";
        /// <summary>
        /// 告警标题ID，alarm_title_table表对应
        /// </summary>
        public string alarmTitleId { get; set; } = "0";
        /// <summary>
        /// 子系统ID
        /// </summary>
        public string subSysId { get; set; } = "";
        /// <summary>
        /// 设备类型ID，device_type_info对应
        /// </summary>
        public string devTypeId { get; set; } = "";
        /// <summary>
        /// 告警描述明细，对应dynamic_data表alarm_describe
        /// </summary>
        public string alarmDesc { get; set; } = "";
        /// <summary>
        /// 告警级别
        /// 原始
        /// </summary>
        public string alarmLevel { get; set; } = "0";
        /// <summary>
        /// 当前实际告警级别
        /// 告警开始时和alarmLevel一致
        /// 告警级别会提升
        /// 具体规则详见alarm_basic_rules表
        /// </summary>
        public string alarmLevelReal { get; set; } = "0";
        /// <summary>
        /// 告警级别会提升规则ID
        /// </summary>
        public string ruleId { get; set; } = "0";
        /// <summary>
        /// 告警级别提升时间记录
        /// </summary>
        public Dictionary<string, DateTime> alarmChanges { get; set; } = new();
        /// <summary>
        /// 告警开始时间
        /// </summary>
        public DateTime GetTime { get; set; } = DateTime.Now;
        /// <summary>
        /// 告警最新更新时间或结束时间
        /// </summary>
        public DateTime UpdTime { get; set; } = DateTime.Now;
        public DateTime changeTime { get; set; } = DateTime.Now;
        /// <summary>
        /// 告警是否结束
        /// </summary>
        public bool isEnd { get; set; } = false;
        /// <summary>
        /// 是否在播出时间
        /// 此状态[发生告警时]的是否在时间表内状态
        /// </summary>
        public bool isInTime { get; set; } = false;
        /// <summary>
        /// 实时是否需要报送告警到前台
        /// 此状态实际上为[实时]是否在时间表内状态
        /// </summary>
        public bool alarm { get; set; } = true;
        /// <summary>
        /// 是否在时间表内告警过，告警历史保存的时候用
        /// 就是开始或结束时间在播出时间内，或者持续时间曾经在播出时间告警过
        /// </summary>
        public bool inTimeAlarm { get; set; } = false;
        /// <summary>
        /// 实时
        /// 月末停播标识
        /// 停机检修时间，0没有，1每月倒数第一周，2每月倒数第二周
        /// 0:false，1、2:true
        /// </summary>
        public bool loopAlarm { get; set; } = false;
        /// <summary>
        /// 参数
        /// 月末停播标识
        /// 停机检修时间，0没有，1每月倒数第一周，2每月倒数第二周
        /// </summary>
        public int loopAlarmType { get; set; } = 0;
        /// <summary>
        /// 是否启用标志
        /// </summary>
        public bool loopAlarmFlag { get; set; } = false;
        /// <summary>
        /// 动态（参数录入）停播标识，用于台站因各种原因随时可能产生的停播
        /// 包含onceFreqAlarm，因为台站级别高于频率
        /// </summary>
        public bool onceStationAlarm { get; set; } = false;
        /// <summary>
        /// 动态（参数录入）停播标识，用于频率因各种原因随时可能产生的停播
        /// 被onceStationAlarm包含
        /// </summary>
        public bool onceFreqAlarm { get; set; } = false;
        /// <summary>
        /// 是否清除告警
        /// </summary>
        public bool clear { get; set; } = false;
        /// <summary>
        /// 告警持续时间，超过才算真正告警
        /// </summary>
        public int alarmTimeout { get; set; } = 15;
        /// <summary>
        /// 结束持续时间，超过才算真正结束
        /// </summary>
        public int alarmEndTimeout { get; set; } = 5;
        /// <summary>
        /// 上次是否告警
        /// 此状态仅仅是根据状态值判断出来的，这里只做记录，不作为最终告警
        /// </summary>
        public bool alarmPre { get; set; } = false;
        /// <summary>
        /// 实际告警状态
        /// </summary>
        public bool alarmReal { get; set; } = false;
        /// <summary>
        /// 该告警条目包含的其他信息
        /// 以字典形式保存，以便于兼容扩展
        /// </summary>
        public Dictionary<string, string> alarmInfo { get; set; } = new Dictionary<string, string>(CommonUtil.mAlarmInfo);
        /// <summary>
        /// 连续两次告警或者不告警、且持续时间超过alarmTimeout秒才算
        /// 只针对普通告警，不针对衍生告警
        /// </summary>
        /// <param name="currentAlarm"></param>
        /// <param name="newTime"></param>
        /// <param name="timtOutPara">
        /// 是超时（离线判断）时，不用判断，用当前时间
        /// </param>
        public bool CheckAlarm(bool currentAlarm, DateTime newTime, bool timtOutPara)
        {
            //告警有变化时，赋值开始、结束时间
            if (currentAlarm != alarmPre)
            {
                //告警跳动时间记录
                changeTime = newTime;

                //当前为告警、已结束的，则认为新告警开始
                if (currentAlarm && !alarmReal)
                { 
                    //跳变，且当前告警，且历史非告警时，记录开始时间
                    GetTime = newTime;
                    alarmKey = System.Guid.NewGuid().ToString("N").ToUpper();
                }
            }

            bool alarmRealPre = alarmReal;
            //特殊的，如timtOutPara超时参数
            bool specPara = (timtOutPara && (currentAlarm || (currentAlarm != alarmReal && currentAlarm == alarmPre && newTime == UpdTime)));
            //更新时间每次都记录

            //当前如果告警，则用告警持续时间，否则用告警结束持续时间
            int timeout = currentAlarm ? alarmTimeout : alarmEndTimeout;
            UpdTime = (specPara || (DateTime.Now - newTime).TotalSeconds > timeout) ? DateTime.Now : newTime;
            //告警最新跳动时间，主要用于判断告警
            TimeSpan ts = UpdTime - changeTime;
            //告警持续时间是否超过设定的间隔
            alarmReal = ts.TotalSeconds > timeout ? currentAlarm : alarmReal;
            //结束一瞬间，UpdTime要减去防抖动的时间
            if (alarmRealPre != alarmReal && !alarmReal && !specPara && !timtOutPara)
            {
                //UpdTime = UpdTime.AddSeconds(-1 * timeout);
                //直接用跳变时的时间
                UpdTime = changeTime;
            }

            //记录当前状态
            alarmPre = currentAlarm;
            //如果是清除
            if (clear)
            {
                alarmPre = false;
                alarmReal = false;
            }
            return alarmReal;
        }
        /// <summary>
        /// 检查alarmInfo字段，避免因为CommonUtil.mAlarmInfo新增了告警字段而造成报错
        /// </summary>
        public void CheckAlarmInfo()
        {
            foreach (string key in CommonUtil.mAlarmInfo.Keys)
            {
                if (!alarmInfo.ContainsKey(key))
                {
                    alarmInfo.TryAdd(key, CommonUtil.mAlarmInfo[key]);
                }
            }

            if (CommonUtil.mAlarmInfo.Count != alarmInfo.Count)
            {
                List<string> lsKey = new List<string>();
                foreach (string key in alarmInfo.Keys)
                {
                    if (!CommonUtil.mAlarmInfo.ContainsKey(key))
                    {
                        lsKey.Add(key);
                    }
                }
                foreach (string key in lsKey)
                {
                    alarmInfo.Remove(key);
                }
            }
        }

        /// <summary>
        /// 返回当前是否推送告警
        /// </summary>
        /// <param name="loopAlarmPush"></param>
        /// <param name="alarmRm"></param>
        /// <returns></returns>
        public bool GetAlarmPush(bool loopAlarmPush, Dictionary<string, bool> alarmRm = null)
        {
            //loopAlarmPush是否启用loopAlarm参数（loopAlarmPush=false时启用）
            return !isEnd &&
                alarm &&
                !onceStationAlarm &&
                !onceFreqAlarm &&
                (loopAlarmPush || !loopAlarm) &&
                isOpen != 2 &&
                (alarmRm == null || !alarmRm.ContainsKey(alarmCode));
        }

        /// <summary>
        /// 根据历史表字段，填充数据 涛思数据库和返回前端
        /// </summary>
        public Dictionary<string, string> GetAlarmHisInfo()
        {
            Dictionary<string, string> alarmDict = new(CommonUtil.mAlarmHisCols);
            alarmDict["ts"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", DateTime.Now) + "'";
            alarmDict["alarm_key"] = "'" + alarmKey + "'";
            alarmDict["isInTime"] = isInTime.ToString();
            alarmDict["alarm"] = alarm.ToString();
            alarmDict["clear"] = clear.ToString();
            alarmDict["get_time"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", GetTime) + "'";
            alarmDict["upd_time"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", UpdTime) + "'";
            alarmDict["parentAlarm_key"] = "'" + parentAlarmKey + "'";
            alarmDict["alarm_code"] = "'" + alarmCode + "'";
            alarmDict["alarm_name"] = "'" + alarmName + "'";
            alarmDict["alarm_title"] = "'" + alarmTitle + "'";
            alarmDict["alarm_desc"] = "'" + alarmDesc + "'";
            alarmDict["alarm_level"] = alarmLevel;
            alarmDict["real_level"] = alarmLevelReal;
            alarmDict["alarm_value"] = "'" + alarmInfo["alarm_value"] + "'";
            alarmDict["alarm_id"] = alarmInfo["alarm_id"];
            alarmDict["alarm_type"] = "".Equals(alarmInfo["alarm_type"]) ? "0" : alarmInfo["alarm_type"];
            alarmDict["station_id"] = "'" + alarmInfo["station_id"] + "'";
            alarmDict["station_name"] = "'" + alarmInfo["station_name"] + "'";
            alarmDict["subcenter_id"] = "'" + alarmInfo["subcenter_id"] + "'";
            alarmDict["dept_id"] = "'" + alarmInfo["dept_id"] + "'";
            alarmDict["station_level"] = alarmInfo["station_level"];
            alarmDict["position_id"] = "'" + alarmInfo["position_id"] + "'";
            alarmDict["frequency"] = "'" + alarmInfo["frequency"] + "'";
            alarmDict["sub_system_id"] = "".Equals(subSysId) ? "-1" : subSysId;
            alarmDict["device_type_id"] = "".Equals(devTypeId) ? "-1" : devTypeId;
            alarmDict["program_name"] = "'" + alarmInfo["program_name"] + "'";
            alarmDict["program_summary"] = "'" + alarmInfo["program_summary"] + "'";
            alarmDict["program_level"] = "".Equals(alarmInfo["program_level"]) ? "-1" : alarmInfo["program_level"];
            alarmDict["device_type"] = "'" + alarmInfo["device_type"] + "'";
            alarmDict["alarm_duration"] = "'" + (UpdTime - GetTime).TotalSeconds.ToString() + "'";
            alarmDict["schemaname"] = "'" + alarmInfo["schemaName"] + "'";
            alarmDict["parno"] = "'" + alarmInfo["parno"] + "'";
            alarmDict["parno_alias"] = "'" + alarmInfo["parno_alias"] + "'";
            alarmDict["alarm_locate"] = "'" + alarmInfo["alarm_locate"] + "'";

            return alarmDict;
        }

        /// <summary>
        /// 根据历史表字段，填充数据 达梦数据库
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> GetAlarmHisInfoDM()
        {
            Dictionary<string, string> alarmDict = new(CommonUtil.mAlarmHisCols);
            alarmDict["ts"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", DateTime.Now) + "'";
            alarmDict["alarm_key"] = "'" + alarmKey + "'";
            alarmDict["isInTime"] = isInTime ? "1" : "0";
            alarmDict["alarm"] = isInTime ? "1" : "0";
            alarmDict["clear"] = isInTime ? "1" : "0";
            alarmDict["get_time"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", GetTime) + "'";
            alarmDict["upd_time"] = "'" + string.Format("{0:yyyy-MM-dd HH:mm:ss.ffffff}", UpdTime) + "'";
            alarmDict["parentAlarm_key"] = "'" + parentAlarmKey + "'";
            alarmDict["alarm_code"] = "'" + alarmCode + "'";
            alarmDict["alarm_name"] = "'" + alarmName + "'";
            alarmDict["alarm_title"] = "'" + alarmTitle + "'";
            alarmDict["alarm_desc"] = "'" + alarmDesc + "'";
            alarmDict["alarm_level"] = alarmLevel;
            alarmDict["real_level"] = alarmLevelReal;
            alarmDict["alarm_value"] = "'" + alarmInfo["alarm_value"] + "'";
            alarmDict["alarm_id"] = alarmInfo["alarm_id"];
            alarmDict["alarm_type"] = "".Equals(alarmInfo["alarm_type"]) ? "0" : alarmInfo["alarm_type"];
            alarmDict["station_id"] = "'" + alarmInfo["station_id"] + "'";
            alarmDict["station_name"] = "'" + alarmInfo["station_name"] + "'";
            alarmDict["subcenter_id"] = "'" + alarmInfo["subcenter_id"] + "'";
            alarmDict["dept_id"] = "'" + alarmInfo["dept_id"] + "'";
            alarmDict["station_level"] = alarmInfo["station_level"];
            alarmDict["position_id"] = "'" + alarmInfo["position_id"] + "'";
            alarmDict["frequency"] = "'" + alarmInfo["frequency"] + "'";
            alarmDict["sub_system_id"] = "".Equals(subSysId) ? "-1" : subSysId;
            alarmDict["device_type_id"] = "".Equals(devTypeId) ? "-1" : devTypeId;
            alarmDict["program_name"] = "'" + alarmInfo["program_name"] + "'";
            alarmDict["program_summary"] = "'" + alarmInfo["program_summary"] + "'";
            alarmDict["program_level"] = "".Equals(alarmInfo["program_level"]) ? "-1" : alarmInfo["program_level"];
            alarmDict["device_type"] = "'" + alarmInfo["device_type"] + "'";
            alarmDict["alarm_duration"] = "'" + (UpdTime - GetTime).TotalSeconds.ToString() + "'";
            alarmDict["schemaname"] = "'" + alarmInfo["schemaName"] + "'";
            alarmDict["parno"] = "'" + alarmInfo["parno"] + "'";
            alarmDict["parno_alias"] = "'" + alarmInfo["parno_alias"] + "'";
            alarmDict["alarm_locate"] = "'" + alarmInfo["alarm_locate"] + "'";

            return alarmDict;
        }

        /// <summary>
        /// 不带单引号，需要返回到前端的
        /// 通常是实时告警
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, string> GetAlarmInfo()
        {
            return GetAlarmHisInfo().ToDictionary(d => d.Key, d => (!isEnd && "upd_time".Equals(d.Key)) ? "" : d.Value.Replace("'", ""));
        }
    }
}
